import * as _ from "lodash"
import { useThemeStore } from "@/stores/theme"
import VariableName from "@/stores/theme/variable-name"
import { WindowPosition } from "@/core/window/window-position"
import { WindowResizeProcessor, type WindowResizeType } from "@/core/window/window-resize-processor"
import WindowProps from "@/core/window/window-props"
import type { Application } from "@/core/application/application"
import type { WindowContent } from "@/core/window/window-content"
import type ThemeTypes from "@/model/theme/types"

export type WindowStatus = "fullscreen" | "minimize" | "maximize" | "default"

export class Window {
  readonly id: string
  readonly application: Application
  readonly content: WindowContent
  readonly position: WindowPosition
  readonly lastPosition: WindowPosition
  theme: ThemeTypes.Type = "auto"
  private status: WindowStatus
  private lastStatus: WindowStatus
  readonly parent: Window | undefined
  readonly children: Map<string, Window> = new Map()

  private resizeProcessor: WindowResizeProcessor | undefined

  readonly props: WindowProps | undefined

  constructor(
    id: string = _.uniqueId("window_"),
    application: Application,
    content: WindowContent,
    props?: WindowProps,
    parent?: Window
  ) {
    this.id = id
    this.application = application
    this.content = content
    this.position = content.size.toPosition()
    this.lastPosition = content.size.toPosition()
    this.parent = parent
    this.status = "default"
    this.lastStatus = "default"
    this.props = props
    this.application.windowContext.activeProcessor.active(this.id)
  }

  //创建子窗口

  createChildWindow(content: WindowContent, props?: WindowProps) {
    const window = new Window(undefined, this.application, content, props, this)
    this.children.set(window.id, window)
  }

  setTheme(theme: ThemeTypes.Type) {
    this.theme = theme
  }

  getStatus() {
    return this.status
  }

  switchMinimize() {
    if (!this.content.size.minimize || this.parent) {
      return
    }
    if (this.status === "minimize") {
      this.status = this.lastStatus
    } else {
      this.lastStatus = this.status
      this.status = "minimize"
      if (this.application.isHidden()) {
        this.application.applicationContext.activeProcessor.inactive()
        this.application.windowContext.activeProcessor.inactive()
      }
    }
  }

  switchMaximize() {
    if (!this.content.size.maximize) {
      return
    }
    if (this.status === "maximize") {
      this.status = this.lastStatus
      this.position.setAll(this.lastPosition)
    } else {
      this.lastStatus = this.status
      this.lastPosition.setAll(this.position)
      this.status = "maximize"
      const maximizePosition = WindowPosition.createMaximizePosition()
      if (!this.content.size.resizeVertical) {
        maximizePosition.top = this.position.top
        maximizePosition.bottom = this.position.bottom
      }
      if (!this.content.size.resizeHorizontal) {
        maximizePosition.left = this.position.left
        maximizePosition.right = this.position.right
      }
      this.position.setAll(maximizePosition)
    }
  }

  //如果不是全屏则切换为全屏，如果时全屏则切换回之前的状态
  switchFullscreen() {
    if (!this.content.size.fullscreen) {
      return
    }
    if (this.status === "fullscreen") {
      this.status = this.lastStatus
      this.position.setAll(this.lastPosition)
      useThemeStore().setVariable(VariableName.Dock.autoHide, "false")
    } else {
      this.lastStatus = this.status
      this.status = "fullscreen"
      this.lastPosition.setAll(this.position)
      this.position.setAll(WindowPosition.createFullscreenPosition())
      useThemeStore().setVariable(VariableName.Dock.autoHide, "true")
    }
  }

  close() {
    if (this.parent) {
      this.parent.children.delete(this.id)
    } else {
      this.application.windowContext.closeWindow(this.id)
    }
  }

  startResize(type: WindowResizeType, event: MouseEvent) {
    this.resizeProcessor = new WindowResizeProcessor(this.position, this.content.size, type, event)
  }

  stopResize() {
    this.resizeProcessor = undefined
  }

  isOnResize() {
    return !!this.resizeProcessor
  }

  resize(event: MouseEvent) {
    if (this.resizeProcessor) {
      this.resizeProcessor.resize(event)
    }
  }

  active() {
    this.application.windowContext.activeProcessor.active(this.id)
  }

  isActive() {
    return (
      this.application.isActive() &&
      this.application.windowContext.activeProcessor.getActiveWindowId() === this.id
    )
  }

  public zIndex() {
    return this.application.windowContext.activeProcessor.getZIndex(this.id)
  }

  static formState(obj: any, application: Application, parent?: Window) {
    const windowContent = application.info.content.windowContents.get(obj.content)
    if (!windowContent) {
      return undefined
    }
    const props = WindowProps.fromState(obj.props)
    const window = new Window(obj.id, application, windowContent, props, parent)

    window.position.setAll(WindowPosition.fromState(obj.position))
    window.lastPosition.setAll(WindowPosition.fromState(obj.lastPosition))
    window.status = obj.status
    window.lastStatus = obj.lastStatus
    const children = Window.fromState4Children(obj.children, application, window)
    if (children) {
      for (const [key, value] of children) {
        window.children.set(key, value)
      }
    }
    return window
  }

  static fromState4Children(obj: any, application: Application, parent: Window) {
    if (!obj) {
      return undefined
    }
    const children = new Map<string, Window>()
    _.forEach(obj, (key: string, value: any) => {
      const window = Window.formState(value, application, parent)
      if (!window) {
        return
      }
      children.set(key, window)
    })
    return children
  }

  toState(): any {
    const obj: any = {}
    obj.id = this.id
    obj.content = this.content.name
    obj.props = this.props
    obj.position = this.position.toState()
    obj.lastPosition = this.lastPosition.toState()
    obj.status = this.status
    obj.lastStatus = this.lastStatus
    obj.children = this.toState4Children()
    obj.props = this.props?.toState()
    return obj
  }

  private toState4Children() {
    const obj: any = {}
    for (const [key, value] of this.children) {
      obj[key] = value.toState()
    }
    return obj
  }
}
